package service

import (
	"context"
	"fmt"
	"net/http"
	"time"
	bclient "zxs-micro-2/zxs-micro-business-client/client"
	"zxs-micro-2/zxs-micro-common/zxsContext"
	"zxs-micro-2/zxs-micro-proto/balancepb/balance"
	"zxs-micro-2/zxs-micro-proto/serverfindpb/serverfind"
	"zxs-micro-2/zxs-micro-wangguan/consts"
	"zxs-micro-2/zxs-micro-wangguan/options"
	_ "zxs-micro-2/zxs-micro-wangguan/traffic_restriction"
)

func ServerHTTP() {
	http.HandleFunc("/", IndexHandler)
	err := http.ListenAndServe("127.0.0.1:8100", nil)
	fmt.Println(err)
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	//处理ctx->处理请求数据->处理数据流转链路->发送请求->处理返回信息->http返回
	ctx := zxsContext.ParseToHttpContext(r.Context(), r, w)
	var err error
	for _, opt := range options.CtxOptions {
		ctx, err = opt(ctx)
		if err != nil {
			w.Write([]byte("something went wrong:" + err.Error()))
			return
		}
	}
	ctx, err = handleRoute(ctx)
	if err != nil {
		w.Write([]byte("something went wrong:" + err.Error()))
		return
	}
	msg, ok := ctx.Value(zxsContext.CTX_MSG_KEY).(*zxsContext.ZxsContextMsg)
	if !ok {
		//fmt.Println("msg???")
		return
	}
	server, ok := msg.GetValue(consts.WANGGUAN_ROUTE_HTTP_GOTO_CTX_KEY).(*serverfind.ServerStruct)
	if !ok {
		//fmt.Println("server???")
		return
	}
	bclient.InitBusinessClient(server)
	bc := bclient.GetClient(server.ServerId)
	ctx, cancle := context.WithTimeout(ctx, time.Second*30)
	var bserr = make(chan error)
	var rsp = make(chan []byte)
	go func() {
		var r []byte
		r, err = bclient.ExecBusiness(ctx, bc, msg.GetValue(zxsContext.CTX_REQUEST_VALUE_KEY).(map[string]interface{}),
			msg.GetValue(zxsContext.CTX_CONTEXT_OPTION_KEY).(map[string]interface{}),
			msg.GetValue(zxsContext.CTX_CONTEXT_REQ_HEAD_KEY).([]byte))
		if err != nil {
			bserr <- err
		} else {
			rsp <- r
		}
	}()
	select {
	case <-ctx.Done():
		w.Write([]byte("time out!"))
	case m := <-rsp:
		w.Write(m)
	case err = <-bserr:
		w.Write([]byte(err.Error()))
	}
	cancle()
}

//先从服务发现找到所有能去的路径，然后通过额外options获取灰度发布相关路径，最后通过负载均衡确定路径
func handleRoute(ctx context.Context) (context.Context, error) {
	msg, ok := ctx.Value(zxsContext.CTX_MSG_KEY).(*zxsContext.ZxsContextMsg)
	if !ok {
		//不是zxs-micro的ctx。。。为什么？
		return ctx, zxsContext.UnknownContextError
	}
	head, ok := msg.GetValue(zxsContext.CTX_HTTP_HEAD_KEY).(*zxsContext.ZxsHttpHead)
	if !ok {
		//表示这里没有成功获取到请求参数，ctx处理有问题
		return ctx, consts.ErrorSomethingWentWrong
	}
	accessRoute := head.Request.URL.Path[1:]
	serverList, err := s.sfClient.QueryServerListByType(ctx, &serverfind.QueryServerListByTypeRequest{
		ServerType: accessRoute,
	})
	if err != nil {
		return ctx, err
	}
	if len(serverList.ServerList) == 0 {
		fmt.Println(accessRoute + "的服务数为0")
		return ctx, nil
	}
	ids := make([]string, len(serverList.ServerList))
	idIp := make(map[string]*serverfind.ServerStruct)
	for i, o := range serverList.ServerList {
		ids[i] = o.ServerId
		idIp[o.ServerId] = o
	}
	msg.AddValue(consts.WANGGUAN_ROUTE_SERVER_ID_GOTO_CTX_KEY, ids)
	for _, opt := range options.RouteOptions {
		ctx, err = opt(ctx)
		if err != nil {
			return ctx, err
		}
	}
	ids, ok = msg.GetValue(consts.WANGGUAN_ROUTE_SERVER_ID_GOTO_CTX_KEY).([]string)
	if !ok {
		//这里能不ok只能说明opt写错了
		return ctx, consts.ErrorSomethingWentWrong
	}
	afterBalanceServerList, err := s.lbClient.CalBalance(ctx, &balance.CalBalanceRequest{
		ServerIds: ids,
	})
	if err != nil {
		return ctx, err
	}
	ipAddr, ok := idIp[afterBalanceServerList.ServerId]
	if !ok {
		//由于负载均衡是业务服务自行注册心跳的，所以服务关闭到负载均衡清理服务记录有时间间隔
		//所以如果没有取到对应信息则直接使用发现的第一个服务
		ipAddr = idIp[ids[0]]
	}
	msg.AddValue(consts.WANGGUAN_ROUTE_HTTP_GOTO_CTX_KEY, ipAddr)
	ctx = context.WithValue(ctx, zxsContext.CTX_MSG_KEY, msg)
	return ctx, nil
}
